package org.flexthinker.binding.value.support
{
    import mx.collections.ArrayCollection;
    import mx.collections.ArrayList;

    import org.hamcrest.assertThat;
    import org.hamcrest.core.not;
    import org.hamcrest.core.throws;
    import org.hamcrest.object.equalTo;
    import org.hamcrest.object.instanceOf;

    public class BufferedCollectionValueModelTest
    {
        private var vm:BufferedCollectionValueModel;
        private var mockBean:MockBean;
        private var listener:PropertyChangeListenerCounter;

        public function BufferedCollectionValueModelTest()
        {
        }

        [Before]
        public function setUp():void
        {
            mockBean = new MockBean();
            listener = new PropertyChangeListenerCounter();
        }

        [Test]
        public function testCreation():void
        {
            assertThat("null buffered value model shouldn't be permitted",
                    function():void
                    {
                        vm = new BufferedCollectionValueModel(null, ArrayList);
                    },
                    throws(instanceOf(Error)));

            assertThat("null wrapped type shouldn't be permitted",
                    function():void
                    {
                        vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleList"), null);
                    },
                    throws(instanceOf(Error)));

            assertThat("non IList wrapped types shouldn't be permitted",
                    function():void
                    {
                        vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleList"), String);
                    },
                    throws(instanceOf(Error)));

            mockBean.simpleString = "123";

            assertThat("non IList values of ValueModels shouldn't be permitted",
                    function():void
                    {
                        vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleString"),
                                ArrayCollection);
                    },
                    throws(instanceOf(Error)));

        }

        [Test]
        public function testWithNullCollection():void
        {
            vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleList"), ArrayCollection);
            vm.addValueChangeListener(listener);
            assertThat("should not be buffering before any change", vm.isBuffering(), equalTo(false));
            assertThat("listener shouldn't be called", listener.counter, equalTo(0));

            vm.setValue(new ArrayCollection([1,2,3]));
            assertThat("should be buffering", vm.isBuffering(), equalTo(true));
            assertThat("listener should be called", listener.counter, equalTo(1));

            mockBean.simpleList = new ArrayCollection(["a","b"]);
            assertThat("should not be buffering when bean changes", vm.isBuffering(), equalTo(false));
            assertThat("listener should be called when bean changed", listener.counter, equalTo(2));
        }

        [Test]
        public function testWithEmptyCollection():void
        {
            mockBean.simpleList = new ArrayCollection();
            vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleList"), ArrayList);
            vm.addValueChangeListener(listener);

            assertThat("should not be buffering before any change", vm.isBuffering(), equalTo(false));
            assertThat("listener shouldn't be called", listener.counter, equalTo(0));

            ArrayList(vm.getValue()).addItem(10);
            assertThat("listener should be called when item is added", listener.counter, equalTo(1));
        }

        [Test]
        public function testWithFilledCollection():void
        {
            mockBean.simpleList = new ArrayCollection([1,2,3]);
            vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleList"), ArrayCollection);
            vm.addValueChangeListener(listener);
            assertThat("should not be buffering before any change", vm.isBuffering(), equalTo(false));
            assertThat("listener shouldn't be called", listener.counter, equalTo(0));

            ArrayCollection(vm.getValue()).addItem(50);
            assertThat("listener should be called when item is added", listener.counter, equalTo(1));
            assertThat("should be buffering", vm.isBuffering(), equalTo(true));

            ArrayCollection(vm.getValue()).removeItemAt(3);
            assertThat("listener should be called when item is removed", listener.counter, equalTo(2));
            assertThat("should not be buffering", vm.isBuffering(), equalTo(false));
        }

        [Test]
        public function testCommit():void
        {
            mockBean.simpleList = new ArrayCollection([1,2,3]);
            vm = new BufferedCollectionValueModel(new ValueHolder(mockBean, "simpleList"), ArrayCollection);
            vm.addValueChangeListener(listener);

            ArrayCollection(vm.getValue()).addItem(50);
            assertThat("should be buffering when list changes", vm.isBuffering(), equalTo(true));
            vm.commit();
            assertThat("should not be buffering after commit", vm.isBuffering(), equalTo(false));
            assertThat("committed collection shouldn't have same ref with the bean's collection", mockBean.simpleList,
                    not(equalTo(vm.getValue())));

            assertThat("committed collections should be similar",
                    new ListValueChangeDetector().hasValueChanged(vm.getValue(), mockBean.simpleList), equalTo(false));
        }
    }
}
